#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <sys/stat.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <Imlib2.h>

#define PICTURES_DIR "~/Pictures"

// Expand tilde in path (e.g., ~/Pictures -> /home/user/Pictures)
char *expand_tilde(const char *path)
{
    if (path[0] != '~')
    {
        return strdup(path);
    }

    const char *home = getenv("HOME");
    if (!home)
    {
        fprintf(stderr, "Error: HOME environment variable not set\n");
        return NULL;
    }

    char *expanded = malloc(strlen(home) + strlen(path) + 1);
    if (!expanded)
    {
        perror("malloc failed");
        return NULL;
    }

    strcpy(expanded, home);
    strcat(expanded, path + 1); // Skip the tilde
    return expanded;
}

// List image files in ~/Pictures
void list_images()
{
    char *pics_dir = expand_tilde(PICTURES_DIR);
    if (!pics_dir)
        return;

    DIR *dir = opendir(pics_dir);
    if (!dir)
    {
        perror("Failed to open Pictures directory");
        free(pics_dir);
        return;
    }

    struct dirent *entry;
    const char *extensions[] = {".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", NULL};
    printf("Available images in %s:\n", pics_dir);

    while ((entry = readdir(dir)) != NULL)
    {
        if (entry->d_name[0] == '.')
            continue; // Skip hidden files

        // Check for image extensions
        for (int i = 0; extensions[i]; i++)
        {
            size_t len = strlen(entry->d_name) - strlen(extensions[i]);
            if (len > 0 && strcmp(entry->d_name + len, extensions[i]) == 0)
            {
                printf("  - %s\n", entry->d_name);
                break;
            }
        }
    }

    closedir(dir);
    free(pics_dir);
}

// Custom X11 root window setter (replaces xsetroot core functionality)
static int set_root_background(Display *dpy, Window root, Pixmap pixmap)
{
    // Set root window's background pixmap
    XSetWindowAttributes attrs;
    attrs.background_pixmap = pixmap;
    XChangeWindowAttributes(dpy, root, CWBackPixmap, &attrs);

    // Clear the window to apply changes
    XClearWindow(dpy, root);

    // Flush X11 commands to ensure they're processed
    XFlush(dpy);
    return 0;
}

// Create a solid color pixmap
static Pixmap create_solid_pixmap(Display *dpy, int screen, unsigned long color)
{
    int width = DisplayWidth(dpy, screen);
    int height = DisplayHeight(dpy, screen);
    Drawable root = RootWindow(dpy, screen);

    Pixmap pixmap = XCreatePixmap(dpy, root, width, height, DefaultDepth(dpy, screen));
    if (!pixmap)
    {
        fprintf(stderr, "Error: Failed to create solid color pixmap\n");
        return None;
    }

    GC gc = XCreateGC(dpy, pixmap, 0, NULL);
    XSetForeground(dpy, gc, color);
    XFillRectangle(dpy, pixmap, gc, 0, 0, width, height);
    XFreeGC(dpy, gc);

    return pixmap;
}

// Create a pixmap from an image file (scaled to screen)
static Pixmap create_image_pixmap(Display *dpy, int screen, const char *image_path)
{
    int screen_width = DisplayWidth(dpy, screen);
    int screen_height = DisplayHeight(dpy, screen);
    Drawable root = RootWindow(dpy, screen);

    // Initialize Imlib2 context
    imlib_context_set_display(dpy);
    imlib_context_set_visual(DefaultVisual(dpy, screen));
    imlib_context_set_colormap(DefaultColormap(dpy, screen));
    imlib_context_set_drawable(root);

    // Load image
    Imlib_Image img = imlib_load_image(image_path);
    if (!img)
    {
        fprintf(stderr, "Error: Could not load image '%s'\n", image_path);
        return None;
    }
    imlib_context_set_image(img);

    // Scale image to screen size
    Imlib_Image scaled = imlib_create_cropped_scaled_image(
        0, 0,
        imlib_image_get_width(), imlib_image_get_height(),
        screen_width, screen_height);
    if (!scaled)
    {
        fprintf(stderr, "Error: Could not scale image\n");
        imlib_free_image();
        return None;
    }
    imlib_context_set_image(scaled);

    // Create pixmap from scaled image
    Pixmap pixmap = XCreatePixmap(
        dpy, root,
        screen_width, screen_height,
        DefaultDepth(dpy, screen));
    if (!pixmap)
    {
        fprintf(stderr, "Error: Failed to create image pixmap\n");
        imlib_free_image();
        imlib_context_set_image(img);
        imlib_free_image();
        return None;
    }

    // Render image to pixmap
    imlib_context_set_drawable(pixmap);
    imlib_render_image_on_drawable(0, 0);

    // Cleanup
    imlib_free_image(); // Free scaled image
    imlib_context_set_image(img);
    imlib_free_image(); // Free original image

    return pixmap;
}

// Main background setter function
int set_background(const char *image_path)
{
    // Open X11 display
    Display *dpy = XOpenDisplay(NULL);
    if (!dpy)
    {
        fprintf(stderr, "Error: Could not open X display (check $DISPLAY)\n");
        return -1;
    }

    int screen = DefaultScreen(dpy);
    Window root = RootWindow(dpy, screen);
    Pixmap pixmap = None;

    // Create appropriate pixmap (image or solid color)
    if (image_path)
    {
        // Use image file
        pixmap = create_image_pixmap(dpy, screen, image_path);
    }
    else
    {
        // Fallback: solid black color
        unsigned long black = BlackPixel(dpy, screen);
        pixmap = create_solid_pixmap(dpy, screen, black);
    }

    if (pixmap == None)
    {
        XCloseDisplay(dpy);
        return -1;
    }

    // Set pixmap as root background
    set_root_background(dpy, root, pixmap);

    // Cleanup
    XFreePixmap(dpy, pixmap); // Free the pixmap (X11 retains a copy)
    XCloseDisplay(dpy);

    if (image_path)
    {
        printf("Background set to: %s\n", image_path);
    }
    else
    {
        printf("Background set to solid black\n");
    }
    return 0;
}

// Show usage instructions
void print_usage(const char *prog_name)
{
    printf("\n%s - Set desktop background from ~/Pictures\n", prog_name);
    printf("Usage: %s [COMMAND] [IMAGE_NAME]\n", prog_name);
    printf("Commands:\n");
    printf("  list         List all images in ~/Pictures\n");
    printf("  set [NAME]   Set background to image from ~/Pictures\n");
    printf("  help         Show this help message\n");
}

int main(int argc, char *argv[])
{
    if (argc == 1)
    {
        print_usage(argv[0]);
        return 0;
    }

    if (strcmp(argv[1], "list") == 0)
    {
        list_images();
        return 0;
    }
    else if (strcmp(argv[1], "set") == 0)
    {
        if (argc != 3)
        {
            fprintf(stderr, "Error: Please specify an image name\n");
            print_usage(argv[0]);
            return 1;
        }

        // Build full path to image
        char *pics_dir = expand_tilde(PICTURES_DIR);
        if (!pics_dir)
            return 1;

        char image_path[PATH_MAX];
        snprintf(image_path, sizeof(image_path), "%s/%s", pics_dir, argv[2]);
        free(pics_dir);

        // Check if image exists
        struct stat st;
        if (stat(image_path, &st) != 0)
        {
            fprintf(stderr, "Error: Image not found - %s\n", image_path);
            return 1;
        }

        return set_background(image_path);
    }
    else if (strcmp(argv[1], "help") == 0)
    {
        print_usage(argv[0]);
        return 0;
    }
    else
    {
        fprintf(stderr, "Error: Unknown command - %s\n", argv[1]);
        print_usage(argv[0]);
        return 1;
    }
}
